/*
Copyright 2009 Swivel4J

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package org.swivel4j.chart;

import static org.apache.commons.lang.StringUtils.isNotBlank;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;

/**
 * Uses Swivel's RESTful API to perform CRUD on Swivel charts.
 * See <a href="http://wiki.github.com/swivel/api/chart-api">
 * Swivel Chart API</a> documentation.
 * @author Ken Weiner
 * @version $Id: RestfulChartClientImpl.java 14 2009-11-30 23:04:14Z kweiner $
 */
public class RestfulChartClientImpl implements ChartClient {
    private HttpClient client;
    
    public RestfulChartClientImpl(String userName, String password) {
    	Credentials credentials = new UsernamePasswordCredentials(userName, password);
    	MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
      	this.client = new HttpClient(connectionManager);
      	this.client.getState().setCredentials(AuthScope.ANY, credentials);
      	this.client.getParams().setAuthenticationPreemptive(true);
    }

	public Chart createChart(String name, String description, String data, Integer groupId, String options) {
        PostMethod method = new PostMethod("https://api.swivel.com/v1/charts.xml");
        
        // Formulate params
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new NameValuePair("name", name));
        if (isNotBlank(description)) {
            params.add(new NameValuePair("description", description));
        }
        if (data != null) {
            params.add(new NameValuePair("data", data));
        }
        if (groupId != null) {
            params.add(new NameValuePair("group_id", groupId.toString()));
        }
        if (isNotBlank(options)) {
            params.add(new NameValuePair("options", options));
        }
        NameValuePair[] paramsArray = params.toArray(new NameValuePair[params.size()]);

        method.setRequestBody(paramsArray);
        try {
			int status = client.executeMethod(method);
			if (status != HttpStatus.SC_CREATED) {
				throw new RuntimeException(
                    "Failed to create chart '" + name + "': HTTP status " + status);
			}
			byte[] responseBody = method.getResponseBody();
			String response = new String(responseBody);
			return new Chart(response);
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			method.releaseConnection();
		}
	}

	public Chart getChartMetadata(Integer chartId) {
        GetMethod method = new GetMethod("https://api.swivel.com/v1/charts/" + chartId + ".xml");
        try {
			int status = client.executeMethod(method);
			if (status != HttpStatus.SC_OK) {
				throw new RuntimeException(
                    "Failed to get metadata for chart " + chartId + ": HTTP status " + status);
			}
			byte[] responseBody = method.getResponseBody();
			String response = new String(responseBody);
			return new Chart(response);
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			method.releaseConnection();
		}
	}

	public String getChartData(Integer chartId) {
        GetMethod method = new GetMethod("https://api.swivel.com/v1/charts/" + chartId + ".csv");
        try {
			int status = client.executeMethod(method);
			if (status != HttpStatus.SC_OK) {
				throw new RuntimeException(
                    "Failed to get data for chart " + chartId + ": HTTP status " + status);
			}
			byte[] responseBody = method.getResponseBody();
			String response = new String(responseBody);
			return response;
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			method.releaseConnection();
		}
	}

	public void replaceChartData(Integer chartId, String data) {
        PutMethod method = new PutMethod("https://api.swivel.com/v1/charts/" + chartId + ".xml");
        NameValuePair[] params = {
            new NameValuePair("data", data)
        };
        method.setQueryString(params);
        try {
			int status = client.executeMethod(method);
			if (status != HttpStatus.SC_OK) {
				throw new RuntimeException(
                    "Failed to replace data for chart " + chartId + ": HTTP status " + status);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			method.releaseConnection();
		}
	}

	public void appendDataToChart(Integer chartId, String data) {
        PutMethod method = new PutMethod("https://api.swivel.com/v1/charts/" + chartId + ".xml");
        NameValuePair[] params = {
            new NameValuePair("mode", "append"),
            new NameValuePair("data", data)
        };
        method.setQueryString(params);
        try {
			int status = client.executeMethod(method);
			if (status != HttpStatus.SC_OK) {
				throw new RuntimeException(
                    "Failed to append data for chart " + chartId + ": HTTP status " + status);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			method.releaseConnection();
		}
	}

	public void deleteChart(Integer chartId) {
        DeleteMethod method = new DeleteMethod("https://api.swivel.com/v1/charts/" + chartId + ".xml");
        try {
			int status = client.executeMethod(method);
			if (status != HttpStatus.SC_OK) {
				throw new RuntimeException(
                    "Failed to delete chart " + chartId + ": HTTP status " + status);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			method.releaseConnection();
		}
	}
}
